package com.polaris.live.ui.party.fragment.game

import android.os.Build
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.os.bundleOf
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.StringUtils
import com.bumptech.glide.Glide
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.core.BasePopupView
import com.polaris.live.R.drawable
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.ext.convertArabicDigitsToNormal
import com.polaris.live.common.ext.dp
import com.polaris.live.common.ext.formatNumberWithK
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.manager.startCountdown
import com.polaris.live.common.network.parseState
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.EventConst
import com.polaris.live.constant.LiveConst
import com.polaris.live.constant.TrackEventConst
import com.polaris.live.constant.ZegoGameEvent
import com.polaris.live.databinding.FragmentPartyGamePlayBinding
import com.polaris.live.dialog.GlobalDialogManager
import com.polaris.live.dialog_fragment.RoomInvitationFragmentDialog
import com.polaris.live.im.manager.ImNoticeManager
import com.polaris.live.im.sfs.bean.live.LiveRoomInfo
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.popup.GameTipsPopup
import com.polaris.live.popup.GlobalPopupManager
import com.polaris.live.popup.InsufficientBalancePopup
import com.polaris.live.popup.PriceModificationPromptPopup
import com.polaris.live.popup.PublicTipsPopup
import com.polaris.live.popup.party.ModifyPricePopup
import com.polaris.live.popup.party.PartyGameBalancePopup
import com.polaris.live.resp.back_resp.PartyGameResp
import com.polaris.live.resp.back_resp.PartyGameSettlementResp
import com.polaris.live.resp.bean.ZegoGameEventBean
import com.polaris.live.translation.R
import com.polaris.live.ui.party.fragment.base.BasePartyGameFragment
import com.polaris.live.ui.party.listener.GamePlayListener
import com.polaris.live.ui.party.listener.GameSeatViewListener
import com.polaris.live.ui.party.widget.seat.SeatBeanUtil
import com.polaris.live.utils.TrackHelper
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.utils.postEvent
import com.polaris.live.utils.zego.LiveEngineManage
import com.polaris.live.utils.zego.listener.PreGameListener
import com.polaris.live.viewmodel.party.game.PartyGamePlayModel
import im.zego.minigameengine.ZegoGameEngineError
import im.zego.minigameengine.ZegoGameLoadState
import im.zego.minigameengine.ZegoGamePlayerState
import im.zego.minigameengine.ZegoGameState
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 玩游戏Fragment
 * @author Created by 天晴 on 2024/3/13 16:29
 * @since 1.0.0
 **/
class GamePlayFragment : BasePartyGameFragment<PartyGamePlayModel, FragmentPartyGamePlayBinding>() {

    private var mLiveInfo: LiveRoomInfo? = null //房间信息
    private var mPartyGameInfo: PartyGameResp? = null //单个游戏信息
    private var mMuteSoundVoice = false
    private var mGameStatus = -1  //游戏状态 0 等待中 1已准备好 2进行中  3已结束
    private var mLocalGameStatus = GAME_UNLOAD  //本地游戏状态
    private var mGameSite = 0  //需要的人数
    private var mGamePlayListener: GamePlayListener? = null

    private var mMeInSeat: Boolean = false //自己在座位
    private var mMeInGame: Boolean = false //自己在游戏中

    private var mStartLoadGameTime = 0L

    private var mIsMatchCome: Boolean? = null//是否是从匹配过来的
    private var mSoundStatus: Boolean? = null//外部传递过来的麦克风状态
    private var mHomeOwnerIsUp = false//房主在创建完房间后是否上座  如果创建完房间上座了后续就不需要管了
    private var mReloadGame = false // 重新加载游戏
    private var mLoadCount = 0 //加载次数

    //是不是房主
    private val mIsAnchor by lazy {
        arguments?.getBoolean(LiveConst.Params.IS_ANCHORID) ?: false
    }

    //结算中界面
    private val mGameBalancePopup by lazy {
        GameTipsPopup(
            requireContext(),
            StringUtils.getString(R.string.game_settlement),
            StringUtils.getString(R.string.game_settlement_tips)
        )
    }

    //开始游戏
    private val mStartGamePopup by lazy {
        GameTipsPopup(
            requireContext(),
            StringUtils.getString(R.string.game_start_settlement),
            StringUtils.getString(R.string.game_start_settlement_tips)
        )
    }

    private var mNowPop: BasePopupView? = null

    private var mOnClickSendGiftCallback: Runnable? = null

    override fun initView(savedInstanceState: Bundle?) {
        mIsMatchCome = arguments?.getBoolean(LiveConst.Params.IS_MATCH_COME_GAME) ?: false
        mSoundStatus = arguments?.getBoolean(LiveConst.Params.SOUND_STATUS) ?: mMuteSoundVoice
        initObserve()
        initListener()

        mBinding.apply {
            editBtn.visibility = if (mIsAnchor) View.VISIBLE else View.GONE
            if (resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
                val lp = goinTv.layoutParams as LinearLayout.LayoutParams
                lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
                goinTv.layoutParams = lp
                jlTv.setBackgroundResource(drawable.rr_r8_e6d1ff)
                jlLl.setBackgroundResource(drawable.ll_r8_back_000000_30)
            }
            if (mIsAnchor) {
                startGame.visibility = View.VISIBLE
            }
        }

        mLiveInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            arguments?.getParcelable(LiveConst.Params.LIVE_INFO, LiveRoomInfo::class.java)
        } else {
            arguments?.getParcelable(LiveConst.Params.LIVE_INFO)
        }


        mSoundStatus?.let {
            mMuteSoundVoice = it
            muteSound()
        }
    }

    /**
     * 数据变化
     */
    fun updateLiveRoomInfo(name: String, liveInfo: LiveRoomInfo) {
        if (isDestroyView()) {
            return
        }
        withLoaded {
            mLiveInfo = liveInfo
            SeatBeanUtil.getGameSeatId(name)?.let {
                updateSeat(liveInfo, it)
                gameCountDownTime()
            }
            when (name) {
                "gameStatus" -> {
                    updateGameStatus(liveInfo.gameStatus ?: 0)
                    if (mGameStatus != 2 && mMeInGame) {
                        mMeInGame = false
                        mGamePlayListener?.gamePlayerStop()
                        reportEvent(ZegoGameEvent.PLAYER_STATE_UPDATE, "1")
                    }
                }

                "gameAsset", "gamePrice" -> { //资产类型 //游戏价格
                    updataAsset(liveInfo)
                }

                "gameStartTime" -> {
                    showStartGameBtn()
                    gameCountDownTime()

                    LogExt.logI(
                        TAG,
                        "gameStartTime: liveId = ${mLiveInfo?.liveId}, gameStartTime = ${liveInfo.gameStartTime}"
                    )
                }
            }
        }
    }

    /**
     * 游戏结算  只在房间关闭时处理
     */
    fun gameResult(data: List<PartyGameSettlementResp>) {

    }

    /**
     * 游戏倒计时 时间判断条件
     */
    private fun gameCountDownTime() {
        if (mLiveInfo?.gameStartTime != null && mLiveInfo?.gameSite == mBinding.playSeatView.getUsers().size) {
            startTimer()
        } else {
            timerJobCancel()
        }
    }

    /**
     * 自己是否在游戏中
     */
    fun isGamePlaying(): Boolean {
        return mMeInGame
    }

    /**
     * 显示价格修改
     */
    fun showPriceModificationPromptPopup(message: String) {
        PriceModificationPromptPopup.show(
            requireContext(),
            message
        ) {
            siteUpDown(true)
        }
    }

    private fun updateGameStatus(gameStatus: Int) {
        if (isDestroyView()) {
            return
        }
        //资源没加载完
        if (mLocalGameStatus < GAME_LOADED) {
            mBinding.playTipsTv.text = StringUtils.getString(R.string.game_resources_loading)
            return
        }
        mGameStatus = gameStatus

        LogExt.logI(
            TAG,
            "updateGameStatus   gameStatus:$gameStatus   mLocalGameStatus：${mLocalGameStatus}   $tag"
        )
        showJoinAndExitUi()
        showStartGameBtn()
        when (gameStatus) {
            0 -> {
                popDismiss()
                timerJobCancel()
                mBinding.playTipsTv.text = StringUtils.getString(R.string.game_wait)

                //匹配进来的用户上座
                if (mIsMatchCome == true) {
                    mIsMatchCome = false
                    mLiveInfo?.userId?.let {
                        mViewModel.liveGameSiteUp(it)
                    }
                }
            }

            1 -> {
                popDismiss()
                mBinding.playTipsTv.text = StringUtils.getString(R.string.begin_in_minute)
            }

            2 -> {
                //在座位还没进入游戏弹窗等待
                if (mMeInSeat && !mMeInGame) {
                    showPop(mStartGamePopup)
                }
            }

            3 -> {
                if (mMeInSeat) { //在座
                    mGamePlayListener?.gamePlayerStop()
                }

                popDismiss()
                mGameResultJob?.cancel()
                mLiveInfo?.liveId?.let {
                    mViewModel.partyGameResult(it)
                }
                mBinding.playTipsTv.text = StringUtils.getString(R.string.in_settlement)
            }

        }
    }

    private var mTimerJob: Job? = null
    private var mRemainingTime = 0L
    private fun startTimer() {
        timerJobCancel()
        val startTime = mLiveInfo?.gameStartTime ?: return
        mRemainingTime = (startTime - CacheUtil.getServerTime()) / 1000
        if (mRemainingTime <= 0) {
            startGo()
            return
        }
        mTimerJob = mViewModel.viewModelScope.startCountdown(mRemainingTime * 1000, 1000L, {
            mBinding.chipLl.visibility = View.INVISIBLE
            mBinding.playTipsTv.text =
                StringUtils.getString(R.string.timer_tips, it / 1000)
                    .convertArabicDigitsToNormal()
        }, {
            if (it <= 0) {
                startGo()
            }
            mBinding.playTipsTv.text = StringUtils.getString(R.string.begin_in_minute)
            mBinding.chipLl.visibility = View.VISIBLE
            if (mTimerJob == coroutineContext[Job]) {
                mTimerJob = null
            }
        })
    }

    /**
     * 取消倒计时
     */
    private fun timerJobCancel() {
        if (isDestroyView()) {
            return
        }
        if (mTimerJob != null) {
            mBinding.chipLl.visibility = View.VISIBLE
            mTimerJob?.cancel()
            mTimerJob = null
        }
    }

    /**
     * 倒计时和点击开始
     */
    private fun startGo() {
        timerJobCancel()
        if (mLiveInfo?.gameStartTime == null) {
            ToastGravity.showGravity(R.string.some_contestants_ready_yet)
            return
        }
        mLiveInfo?.liveId?.let {
            mViewModel.partyGameStart(it, LiveConst.GameBusinessType.LIVE)
        }
    }

    /**
     * 操作声音
     */
    private fun muteSound() {
        if (!isCreated()) {
            return
        }
        mBinding.btnVoice.setImageResource(if (mMuteSoundVoice) drawable.party_voice_close else drawable.party_voice)
        val mute = if (mLocalGameStatus == GAME_START_PLAY) {
            mMuteSoundVoice
        } else {
            true
        }
        val engine = LiveEngineManage.getGameEngineHandler()?.getEngine()
        engine?.apply {
            muteGameSoundEffect(mute)
            muteGameMusic(true)
        }
    }

    private fun updateSeat(liveInfo: LiveRoomInfo, index: Int) {
        val userStr = SeatBeanUtil.getGameSite(liveInfo, index)
        val userBasicVo = userStr?.let { JsonUtils.fromJson<UserBasicVo>(it) }
        mBinding.playSeatView.upDataItem(index, userBasicVo)

        if (userStr.isNullOrEmpty() || userStr == "null") {
            mBinding.playSeatView.upLoadedItem(index, false)
        } else {
            val load = SeatBeanUtil.getGameLoad(liveInfo, index)
            mBinding.playSeatView.upLoadedItem(index, load == null || !load)
        }

        //判断游戏位上是否包含自己
        if (mBinding.playSeatView.getUsers().contains(UserManager.getUserId().toString())) {
            mBinding.startGame.visibility = View.VISIBLE
        } else {
            if (!mIsAnchor) {
                mBinding.startGame.visibility = View.GONE
            }
        }
    }

    /**
     * 重新加载游戏
     */
    fun reloadGame() {
        if (isDestroyView()) {
            return
        }
        mReloadGame = true
        LiveEngineManage.getGameEngineHandler()?.unloadGame(true)

        LogExt.logI(TAG, "reloadGame: liveId = ${mLiveInfo?.liveId}")
    }

    override fun onResume() {
        super.onResume()
        mLiveInfo?.let {
            loadGame(it)
        }
    }

    override fun onPause() {
        super.onPause()
        LiveEngineManage.getGameEngineHandler()?.unloadGame(true)
    }

    /**
     * 加载游戏
     */
    fun loadGame(liveInfo: LiveRoomInfo) {
        if (isDestroyView()) {
            return
        }
        withLoaded {
            val isInit = LiveEngineManage.getGameEngineHandler()?.getEngine()?.isInit
            mLiveInfo = liveInfo

            if (liveInfo.gameStatus == 2 && areYouPresentSeat()) { //在游戏中状态且在座
                mGamePlayListener?.gamePlayerStart()
            }

            loadGameUi(liveInfo)
            if (isInit == true) {
                goToLoadGame(liveInfo)
            } else {
                LiveEngineManage.getGameEngineHandler()?.initEngIne { errorCode, _ ->
                    if (errorCode == 0 || errorCode == ZegoGameEngineError.ERROR_ALREADY_INIT) {
                        goToLoadGame(liveInfo)
                    }
                }
            }

            LogExt.logI(TAG, "loadGame: liveId = ${mLiveInfo?.liveId}, isInit = $isInit")
        }
    }

    /**
     * 查询是否在座
     */
    private fun areYouPresentSeat(): Boolean {
        val liveInfo = mLiveInfo
        return if (liveInfo == null) {
            false
        } else {
            for (index in 0 until 7) {
                val userJson = SeatBeanUtil.getGameSite(liveInfo, index)
                if (!userJson.isNullOrEmpty()) {
                    val userBasicVo: UserBasicVo? = JsonUtils.fromJson<UserBasicVo>(userJson)
                    if (userBasicVo != null && userBasicVo.userId == UserManager.getUserId()) {
                        return true
                    }
                }
            }
            false
        }
    }

    private fun goToLoadGame(liveInfo: LiveRoomInfo) {
        if (isDestroyView()) {
            return
        }
        liveInfo.gameMiniId?.let {
            LiveEngineManage.getGameEngineHandler()?.preloadGame(it, preGameListener.apply {
                setLiveRoomInfo(liveInfo)
            })
        }
        LogExt.logI(
            TAG,
            "goToLoadGame: liveId = ${liveInfo.liveId}, gameId = ${liveInfo.gameMiniId}"
        )
    }

    private val preGameListener = object : PreGameListener {
        var liveInfo: LiveRoomInfo? = null
        fun setLiveRoomInfo(liveInfo: LiveRoomInfo) {
            this.liveInfo = liveInfo
        }

        override fun callback(errorCode: Int, progress: Int) {
            LogExt.logI("--ZegoGame", "preloadGame------$errorCode   $progress-----")
            if (isCreated() && ((errorCode == 0 && progress == 100) || errorCode != 0)) { //预加载失败也直接加载
                liveInfo?.apply {
                    gameMiniId?.also {
                        LiveEngineManage.getGameEngineHandler()
                            ?.loadGame(liveId.toString(), it, mBinding.gameFl) { errorCode ->
                                if (errorCode != ZegoGameEngineError.SUCCESS) {
                                    if (errorCode != ZegoGameEngineError.SUCCESS) {
                                        delayReloadGame()
                                    } else {
                                        mLoadCount = 0
                                    }
                                }
                            }
                        mStartLoadGameTime = System.currentTimeMillis()
                    }
                }
            }
        }
    }
    private var mReloadGameJob: Job? = null
    private var mGameResultJob: Job? = null


    private fun delayReloadGame() {
        mReloadGameJob = mViewModel.viewModelScope.launch {
            try {
                delay(RELOAD_TIME)
                withContext(CoroutineScopeManager.mainDispatcher) {
                    mLoadCount++
                    if (mLoadCount > MAX_LOAD_COUNT) {
                        mLoadCount = 0
                        ToastGravity.showGravity(R.string.game_load_error)
                    } else {
                        reloadGame()
                    }
                }
            } finally {
                if (mReloadGameJob == coroutineContext[Job]) {
                    mReloadGameJob = null
                }
            }
        }

    }

    private fun getGameResultTimer() {
        mGameResultJob?.cancel()
        mGameResultJob = mViewModel.viewModelScope.launch {
            try {
                delay(GAME_TIME)
                mLiveInfo?.liveId?.let {
                    mViewModel.partyGameResult(it)
                }
            } finally {
                if (mGameResultJob == coroutineContext[Job]) {
                    mGameResultJob = null
                }
            }
        }
    }

    /**
     * 设置数据
     */
    private fun loadGameUi(liveInfo: LiveRoomInfo) {
        mBinding.apply {
            view?.post {
                view?.let {
                    var nh = 0
                    when (mLiveInfo?.gameType) {
                        LiveConst.GameType.BLACK8, LiveConst.GameType.DOMINO -> {
                            val h1 = it.height - 190.dp
                            nh = if (it.width > h1) {
                                it.width + 10.dp
                            } else {
                                h1
                            }
                        }

                        LiveConst.GameType.UNNO, LiveConst.GameType.LUDO -> {
                            nh = it.width + 10.dp
                        }
                    }
                    mGamePlayListener?.setMessageHeight(it.height - nh - 45.dp)
                    val lp = zhuoBg.layoutParams as ConstraintLayout.LayoutParams
                    lp.height = nh
                    zhuoBg.layoutParams = lp
                    val lp2 = gameFl.layoutParams as ConstraintLayout.LayoutParams
                    lp2.height = nh
                    gameFl.layoutParams = lp2
                }
            }

            gameCoin.text = UserManager.getUser().account?.userGameCoins.formatNumberWithK()
            userAsset.text = UserManager.getUser().account?.userCoins.formatNumberWithK()

            Glide.with(this@GamePlayFragment)
                .load(ImageUtils.imgPath(liveInfo.gameLogo))
                .centerCrop()
                .into(logo)
            Glide.with(this@GamePlayFragment)
                .load(ImageUtils.imgPath(liveInfo.gameBackground))
                .centerInside()
                .into(zhuoBg)
            liveInfo.gameSite?.let {
                mGameSite = it
                playSeatView.setSeatCount(it)
                for (index in 0 until it) {
                    updateSeat(liveInfo, index)
                }
            }
        }
        updataAsset(liveInfo)
        updateGameStatus(liveInfo.gameStatus ?: 0)

        if (liveInfo.userId == UserManager.getUserId() && !mHomeOwnerIsUp) {
            if (!mMeInSeat) {
                mBinding.joinBtn.performClick()
            }
            mHomeOwnerIsUp = true
        }

        liveInfo.gameType?.let {
            mViewModel.getOnePartyGame(it)
        }
    }

    /**
     * 更新奖励
     */
    private fun updataAsset(liveInfo: LiveRoomInfo) {
        if (liveInfo.gameAsset == 9) {
            mBinding.freeRl.visibility = View.VISIBLE
            mBinding.assetLl.visibility = View.GONE
        } else {
            mBinding.freeRl.visibility = View.GONE
            mBinding.assetLl.visibility = View.VISIBLE
            mBinding.apply {
                if (liveInfo.gameAsset == 0) {
                    assetType.setImageResource(drawable.icon_diamond)
                } else {
                    assetType.setImageResource(drawable.party_game_mod_yxb2)
                }
                goinTv.text = "${liveInfo.gamePrice}"
            }
        }
    }

    /**
     * 开始游戏 服务器返回可开始
     */
    private fun startGame() {
        if (isCreated()) {
            LiveEngineManage.getGameEngineHandler()
                ?.startGame(mLiveInfo?.gameMiniId, mBinding.playSeatView.getUsers()) {
                    if (it != 0) {
                        ToastGravity.showGravity(R.string.game_start_error)
                    }
                }
        }
    }

    /**
     * 控制加入退出按钮
     */
    fun showJoinAndExitUi() {
        mBinding.apply {
            if (mMeInSeat) {
                exitGame.visibility = View.VISIBLE
                joinBtn.visibility = View.GONE
            } else {
                exitGame.visibility = View.GONE
                joinBtn.visibility = View.VISIBLE
            }
        }
    }

    /**
     * 控制开启游戏
     */
    private fun showStartGameBtn() {
        val bg = if (mLiveInfo?.gameStartTime == null) {
            drawable.party_go_gray
        } else {
            when (mLiveInfo?.gameType) {
                LiveConst.GameType.LUDO -> drawable.party_go_bg
                LiveConst.GameType.DOMINO -> drawable.party_go_bg2
                LiveConst.GameType.BLACK8 -> drawable.party_go_bg1
                LiveConst.GameType.UNNO -> drawable.party_go_bg1
                else -> drawable.party_go_bg
            }
        }
        mBinding.startGame.setBackgroundResource(bg)
    }

    private fun initListener() {
        mBinding.apply {
            playSeatView.setOnGameSeatViewListener(object : GameSeatViewListener {
                override fun meChange(seatId: Int?) {
                    mMeInSeat = seatId != null
                    mGamePlayListener?.gamePlayerInSeat(seatId != null)
                    showJoinAndExitUi()
                }

                override fun clickItem(userId: Long?) {
                    if (userId == null) {
                        mLiveInfo?.userId?.let {
                            mViewModel.liveGameSiteUp(it)
                        }
                    } else {
                        mGamePlayListener?.gameSeatClick(userId)
                    }

                }
            })

            startGame.setOnSingleClickListener {
                startGo()
            }

            editBtn.setOnSingleClickListener {
                if (mIsAnchor) {
                    mPartyGameInfo?.let { partyGameInfo ->
                        ModifyPricePopup.show(
                            requireContext(),
                            partyGameInfo,
                            mLiveInfo?.gameAsset,
                            mLiveInfo?.gamePrice
                        ) { type, price ->
                            mLiveInfo?.liveId?.let { userId ->
                                mViewModel.partyGamePrice(userId, price, type)
                            }
                        }
                    } ?: mLiveInfo?.gameType?.let { gameType ->
                        mViewModel.getOnePartyGame(gameType)
                    }
                }
            }
            addDms.setOnSingleClickListener {
                GlobalPopupManager.showRechargePopup(
                    requireContext(),
                    mViewModel,
                    isNeedBottom = true
                )
            }
            exchangeYxb.setOnSingleClickListener {
                showExchangeGamePopup()
            }
            exitGame.setOnSingleClickListener {
                siteUpDown(false)
            }
            btnWen.setOnSingleClickListener {
                mPartyGameInfo?.let { partyGameInfo ->
                    GlobalDialogManager.showGameRuleDialog(
                        requireContext(),
                        partyGameInfo.slogan
                    )
                } ?: mLiveInfo?.gameType?.let { gameType ->
                    mViewModel.getOnePartyGame(gameType)
                }

            }

            btnVoice.setOnSingleClickListener {
                mMuteSoundVoice = !mMuteSoundVoice
                muteSound()
            }
            joinBtn.setOnSingleClickListener {
                siteUpDown(true)
            }
            inviteRl.setOnSingleClickListener {
                mLiveInfo?.liveId?.let { liveId ->
                    val fragmentManager = childFragmentManager
                    RoomInvitationFragmentDialog().apply {
                        arguments = bundleOf("liveId" to liveId)
                    }.show(
                        fragmentManager,
                        "RoomInvitationFragmentDialog"
                    )
                }
            }
        }

    }

    fun setOnClickSendGiftCallback(l: Runnable) {
        this.mOnClickSendGiftCallback = l
    }

    /**
     * 上下位置
     */
    fun siteUpDown(boolean: Boolean) {
        mLiveInfo?.let {
            if (boolean) {
                if (mLocalGameStatus != GAME_START_PLAY) {
                    mViewModel.liveGameSiteUp(it.userId)
                } else {
                    ToastGravity.showGravity(R.string.not_in_operation_time)
                }
            } else {
                if (mMeInSeat) {
                    PublicTipsPopup.show(
                        requireContext(), this,
                        StringUtils.getString(R.string.prompt),
                        StringUtils.getString(R.string.are_you_sure_exit_game_queue),
                        StringUtils.getString(R.string.cancel),
                        StringUtils.getString(R.string.confirm)
                    ) {
                        mViewModel.liveGameSiteDown(it.userId)
                    }
                }
            }
        }

    }

    private fun initObserve() {
        //余额变动
        ImNoticeManager.observeAccountChange(this) {
            mBinding.userAsset.text = UserManager.getUser().account?.userCoins.formatNumberWithK()
        }
        //资产修改
        ImNoticeManager.observeGameAccountChange(this) {
            mBinding.gameCoin.text =
                UserManager.getUser().account?.userGameCoins.formatNumberWithK()
        }
        //上游戏位
        mViewModel.liveGameSiteUpData.observe(this) {
            if (it == 0) return@observe
            mLiveInfo?.gameAsset?.let { type ->
                showInsufficientBalancePopup(type)

                mIsMatchCome = false
            }
        }
        //开始游戏
        mViewModel.partyGameStartData.observe(this) { resultState ->
            parseState(resultState, {
                startGame()
            }, {
                ToastGravity.showGravity(it.errorMsg)
            })
        }
        //获取单个派对游戏
        mViewModel.getOnePartyGameData.observe(this) { resultState ->
            parseState(resultState, {
                mPartyGameInfo = it
            }, {
                ToastGravity.showGravity(it.errorMsg)
            })
        }
        //修改价格
        mViewModel.partyGamePriceData.observe(this) { resultState ->
            if (mIsAnchor) {
                parseState(resultState, {
                    ToastGravity.showGravity(R.string.modified_successfully)
                }, {
                    ToastGravity.showGravity(it.errorMsg)
                })
            }
        }
        //游戏结算
        mViewModel.partyGameResultData.observe(this) { resultState ->
            parseState(resultState, {
                mGameResultJob?.cancel()
                popDismiss()
                PartyGameBalancePopup.show(
                    requireContext(),
                    mLiveInfo?.gameEndWaitSecond ?: 0,
                    it,
                    {
                        siteUpDown(true)
                    },
                    {
                        siteUpDown(true)
                    }, null
                )
            }, {
                ToastGravity.showGravity(it.errorMsg)
            })
        }
    }

    override fun onDestroyView() {
        timerJobCancel()
        mGameResultJob?.cancel()
        mReloadGameJob?.cancel()
        LiveEngineManage.getGameEngineHandler()?.removePreGameListener(preGameListener)
        super.onDestroyView()
    }

    fun setGamePlayListener(listener: GamePlayListener) {
        mGamePlayListener = listener
    }

    private fun showPop(pop: BasePopupView) {
        popDismiss()
        mNowPop = XPopup.Builder(context)
            .isViewMode(true)
            .isDestroyOnDismiss(true)
            .asCustom(pop)
            .show()
    }

    private fun popDismiss() {
        mNowPop?.dismiss()
    }

    private fun showGameUi() {
        popDismiss()
        mBinding.startCl.visibility = View.GONE
        mBinding.gameFl.visibility = View.VISIBLE
    }

    private fun hideGameUi() {
        muteSound()
        mBinding.startCl.visibility = View.VISIBLE
        mBinding.gameFl.visibility = View.INVISIBLE
        showPop(mGameBalancePopup)
    }

    fun exitRoom() {
        if (!isCreated() || isDestroyView()) {
            return
        }
        popDismiss()
        mGameStatus = -1
        mBinding.startCl.visibility = View.VISIBLE
        mBinding.gameFl.visibility = View.INVISIBLE
    }

    /**
     * 余额不足弹窗
     */
    private fun showInsufficientBalancePopup(type: Int) {
        XPopup.Builder(context)
            .hasShadowBg(true)
            .isDestroyOnDismiss(true)
            .asCustom(InsufficientBalancePopup(requireContext(), type, {
                GlobalPopupManager.showRechargePopup(requireContext(), mViewModel, isNeedBottom = true)
            }, {
                showExchangeGamePopup()
            }))
            .show()
    }

    /**
     * 显示兑换游戏币
     */
    private fun showExchangeGamePopup() {
        GlobalPopupManager.showExchangeGamePopup(requireContext(), mViewModel)
    }

    /**
     * =====================游戏回调============================
     */
    override fun onGameError(errorCode: Int, errorMessage: String?) {
        val params = buildMap {
            put("errorCode", errorCode.toString())
            errorMessage?.let {
                put("errorMessage", it)
            }
        }
        reportEvent(ZegoGameEvent.GAME_ERROR, params)

        LogExt.logI(
            TAG,
            "onGameError: ${mLiveInfo?.liveId}, errorCode = $errorCode, errorMessage = $errorMessage"
        )
    }

    override fun onGameLoadStateUpdate(gameLoadState: ZegoGameLoadState?) {
        // 通知游戏加载的状态
        when (gameLoadState) {
            ZegoGameLoadState.ZegoGameLoading -> {
                mLocalGameStatus = GAME_LOAD

                reportEvent(ZegoGameEvent.GAME_LOAD_STATE_UPDATE, "0")
            }

            ZegoGameLoadState.ZegoGameLoaded -> {
                muteSound()

                LiveEngineManage.getGameEngineHandler()?.getEngine()?.setGameComponent(
                    "game_page_top_coin", false
                ) { _, _ -> }
                LiveEngineManage.getGameEngineHandler()?.getEngine()?.setGameComponent(
                    "table_ante", false
                ) { _, _ -> }

                mLocalGameStatus = GAME_LOADED

                updateGameStatus(if (mGameStatus != -1) mGameStatus else 0)

                //上报加载时间
                val duration = System.currentTimeMillis() - mStartLoadGameTime //加载时间
                TrackHelper.postTrack(
                    this@GamePlayFragment,
                    TrackEventConst.GAME_LOAD_TIME,
                    params = TrackHelper.rechargeForMap(mutableMapOf("time" to duration.toString()))
                )
                Firebase.analytics.postEvent(
                    EventConst.ZEGO_GAME_LOAD_DURATION,
                    bundleOf(
                        "time" to duration.toString()
                    )
                )

                reportEvent(ZegoGameEvent.GAME_LOAD_STATE_UPDATE, "1")
            }

            null -> {}
        }

        LogExt.logI(
            TAG,
            "onGameLoadStateUpdate: ${mLiveInfo?.liveId}, gameLoadState = $gameLoadState"
        )
    }

    // 通知游戏运行状态（SDK 版本为 1.4.0 及以上时，推荐使用此回调）
    override fun onGameStateUpdate(gameState: ZegoGameState?, reasonCode: Int) {
        when (gameState) {
            ZegoGameState.ZegoGamePlaying -> {
                if (mLocalGameStatus != GAME_START_PLAY) {
                    mLocalGameStatus = GAME_START_PLAY
                    muteSound()
                    if (!mMeInSeat) {
                        showGameUi()
                    }
                }
            }

            ZegoGameState.ZegoGameOver -> {
                if (mLocalGameStatus != GAME_STOP_PLAY) {
                    getGameResultTimer()
                    mLocalGameStatus = GAME_STOP_PLAY
                    hideGameUi()
                }
            }

            ZegoGameState.ZegoGameIdle -> {
                mLocalGameStatus = GAME_READY
            }

            else -> {}
        }

        val params = buildMap {
            put("reasonCode", reasonCode.toString())
            gameState?.let {
                put("gameState", gameState.ordinal.toString())
            }
        }
        reportEvent(ZegoGameEvent.GAME_STATE_UPDATE, params)

        LogExt.logI(
            TAG,
            "onGameStateUpdate: liveId: ${mLiveInfo?.liveId}, gameState = $gameState, reason = $reasonCode"
        )
    }

    // 通知当前玩家的状态（游戏中/不在游戏中）
    override fun onPlayerStateUpdate(playerState: ZegoGamePlayerState?) {
        when (playerState) {
            ZegoGamePlayerState.ZegoGamePlayerStartPlay -> { //游戏开始
                if (mMeInSeat) {
                    mMeInGame = true
                    muteSound()
                    showGameUi()
                    mGamePlayListener?.gamePlayerStart()

                    reportEvent(ZegoGameEvent.PLAYER_STATE_UPDATE, "0")
                }
            }

            ZegoGamePlayerState.ZegoGamePlayerStopPlay -> {//游戏结束
                if (mMeInSeat) {
                    mMeInGame = false
                    mGamePlayListener?.gamePlayerStop()

                    reportEvent(ZegoGameEvent.PLAYER_STATE_UPDATE, "1")
                }
            }

            null -> {}
        }

        LogExt.logI(
            TAG,
            "onPlayerStateUpdate: liveId = ${mLiveInfo?.liveId}, playerState = $playerState, meInSeat = $mMeInSeat"
        )
    }

    // 通知反加载游戏成功
    override fun onUnloaded(gameID: String?) {
        mLocalGameStatus = GAME_UNLOAD

        if (mReloadGame) {
            mLiveInfo?.let {
                mReloadGame = false
                if (LiveEngineManage.getGameEngineHandler()?.getEngine()?.isInit == true) {
                    goToLoadGame(it)
                } else {
                    LiveEngineManage.getGameEngineHandler()?.initEngIne { errorCode, _ ->
                        if (errorCode == 0 || errorCode == ZegoGameEngineError.ERROR_ALREADY_INIT) {
                            goToLoadGame(it)
                        }
                    }
                }
            }
        }

        LogExt.logI(TAG, "onUnloaded: liveId = ${mLiveInfo?.liveId}, gameId = $gameID")
    }

    override fun onGameResult(result: String?) {
        result?.let {
            reportEvent(ZegoGameEvent.GAME_RESULT, it)
        }
    }

    private fun reportEvent(event: Int, params: Any) {
        val info = mLiveInfo ?: return

        val finalParams = if (params is String) {
            params
        } else {
            JsonUtils.toJson(params)
        }

        mViewModel.zegoGameEvent(
            ZegoGameEventBean(
                info.liveId,
                LiveConst.GameBusinessType.LIVE,
                event,
                finalParams
            )
        )
    }

    companion object {

        const val TAG = "GamePlayFragment"
        const val GAME_UNLOAD = 1000000 //游戏未加载
        const val GAME_LOAD = 1000001 //游戏加载中
        const val GAME_LOADED = 1000002 //游戏加载完成
        const val GAME_START_PLAY = 1000003 //游戏开始
        const val GAME_STOP_PLAY = 1000004 //游戏结束
        const val GAME_READY = 1000005 //游戏空闲
        const val GAME_TIME = 5000L //等待結算时间
        const val MAX_LOAD_COUNT = 10 //加载失败最多加载次数
        const val RELOAD_TIME = 3000L //重试加载时间
    }
}